package cn.alone.user.service.impl;
import cn.alone.basic.BusinessException;
import cn.alone.basic.constant.BaseConstants;
import cn.alone.basic.util.AjaxResult;
import cn.alone.basic.util.HttpClientUtils;
import cn.alone.basic.util.MD5Utils;
import cn.alone.basic.util.StrUtils;
import cn.alone.user.domain.Logininfo;
import cn.alone.user.domain.User;
import cn.alone.user.domain.WxUser;
import cn.alone.user.dto.LoginDto;
import cn.alone.user.mapper.LogininfoMapper;
import cn.alone.user.mapper.UserMapper;
import cn.alone.user.mapper.WxUserMapper;
import cn.alone.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 登录接口
 * @author lanan
 */
@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;
    /**
     * 使用redis
     */
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public Map<String, Object> accountLogin(LoginDto dto) {

        //1.校验 type是识别登录来源的身份必须要有
        if(dto.getType()==null){
            throw new BusinessException("数据异常，请联系管理员");
        }
        //2.根据用户名查询数据库 t_logininfo
        Logininfo logininfo = logininfoMapper.loadByUserName(dto);
        //2.1查询不到报错
        if (logininfo==null){
            throw new BusinessException("用户名不存在，请重新输入");
        }
        //2.2 查询到了,判断密码是否一致 加密之后判断 获取加密后的密码
        String salt = logininfo.getSalt();
        //使用盐值加密用户输入的密码然后做对比
        String mdpsw = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        if(!mdpsw.equals(logininfo.getPassword())){
            throw new BusinessException("密码错误，请重新输入");
        }
        //3.登录成功 存入一个token(用方法自定义生成，独一无二)和redis数据
        String token = UUID.randomUUID().toString();
        //3.1 存redis 设置30分钟有效期
        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
        //3.2 返回登录成功的必要信息
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        //我们作为高级技师,应该需要考虑到,将一些敏感信息屏蔽掉
        logininfo.setPassword(null);
        logininfo.setType(null);
        map.put("logininfo", logininfo);
        return map;
    }

    /**
     * 发送code请求到微信获取令牌
     * @param code
     * @return
     */
    @Override
    public AjaxResult wechat(String code) {
        /*1.根据code携带公司资质和回调域名发送请求*/
        /*1.1获取请求地址*/
        String tokenUrl = BaseConstants.GET_TOKEN_URL
                .replace("APPID", BaseConstants.APPID)
                .replace("SECRET", BaseConstants.SECRET)
                .replace("CODE", code);
        /*1.2发送请求拿到微信返回的json对象,
        拿到对象转换成字符串,获取access_token和openid*/
        String tokenObjStr = HttpClientUtils.httpGet(tokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(tokenObjStr);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        System.out.println("前端传过来的token——————————————————————"+accessToken);
        System.out.println("前端传过来的openid-------------"+openId);
        /*2.根据openId查询t_wxuser看看是否存在登录信息*/
        WxUser wxuser = wxUserMapper.loadByOpenId(openId);
        if (wxuser != null && wxuser.getUser_id() != null) {
            /*存在登录信息,放行*/
            /*2.1存储登录信息token和logininfo并刷新redis时间*/
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUser_id());
            /*注意这个是我们登录返回给locaSt啥啥存的token和微信的不是同一个东西*/
            String token = UUID.randomUUID().toString();
            System.out.println("查询登录信息表==============="+logininfo);
            redisTemplate.opsForValue().set(token,logininfo, 30, TimeUnit.MINUTES);
            /*3.返回登录成功前端需要的信息token和login还有屏蔽掉一些用户的敏感信息*/
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo", logininfo);
            return AjaxResult.me().setResultObj(map);
        } else {
            /*没有登录信息,第一次来跳转到绑定页面*/
            /*拼接到地址里,后面用户绑定给用户注册账号需要用到这两个信息*/
            String binderParams = "?accessToken=" + accessToken + "&openId=" + openId;
            return AjaxResult.me().setSuccess(false).setResultObj(binderParams);
        }
    }

    /**
     * 用户微信绑定
     * @param params
     * @return
     */
    @Override
    public Map<String, Object> binderWechat(Map<String, String> params) {
        /*校验参数*/
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        String accessToken = params.get("accessToken");
        String openId = params.get("openId");
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)){
            throw new BusinessException("参数不能为空");
        }

        /*校验验证码*/
         /*查看验证码是否过期*/
        Object codeTmp = redisTemplate.opsForValue().get(BaseConstants.BUSINESS_BINDER_PREFIX + phone);
        if (codeTmp == null) {
            throw new BusinessException("验证码已失效,请重新获取!");
        }
        /*截取验证码*/
        String code = ((String)codeTmp).split(":")[0];
        /*验证码对比*/
        if(!verifyCode.equalsIgnoreCase(code)){
            throw new BusinessException("验证码错误!!!");
        }

        //查询手机号是否被注册过 t_user
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        if(user != null){
            /*已存在用户绑定*/
            logininfo = logininfoMapper.loadById(user.getLogininfo_id());
        }else{
            /*查询不到做新绑定*/
            user = initUser(phone);
            logininfo = user2Logininfo(user);
            /*保存logininfo 返回自增id*/
            logininfoMapper.save(logininfo);
            /*保存 user*/
            user.setLogininfo_id(logininfo.getId());
            userMapper.save(user);
        }
        /*调用微信,查询用户微信基本信息*/
        String getWxUserURL = BaseConstants.GET_WXUSER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserStr = HttpClientUtils.httpGet(getWxUserURL);
        WxUser wxUser = JSONObject.parseObject(wxUserStr, WxUser.class);
        /*绑定用户信息*/
        wxUser.setUser_id(user.getId());
        wxUserMapper.save(wxUser);
        /*免密登录*/
        String token = UUID.randomUUID().toString();
        /*存储redis设置过期时间*/
        redisTemplate.opsForValue().set(
                token,
                logininfo,
                30,
                TimeUnit.MINUTES
        );
        /*返回token给浏览器*/
        Map<String,Object> map = new HashMap<>();
        map.put("token", token);
        /*屏蔽敏感信息*/
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo", logininfo);
        return map;
    }
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        /*加盐加密初始密码*/
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5("12345" + salt);
        /*短信发送初始密码给用户*/
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }

    /**
     * 同名原则拷贝
     * @param user
     * @return
     */
    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        return logininfo;
    }
}
